package com.unknow.first.dapp.admin.account.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.unknow.first.dapp.admin.account.constants.AccountConstants;
import com.unknow.first.dapp.admin.account.mapper.AddressCoinConfig;
import com.unknow.first.dapp.admin.account.mapper.AddressRecharge;
import com.unknow.first.dapp.admin.account.mapper.AddressRechargeMapper;
import com.unknow.first.dapp.admin.account.service.AddressAccountInfoService;
import com.unknow.first.dapp.admin.account.service.AddressCoinConfigService;
import com.unknow.first.dapp.admin.account.service.AddressRechargeService;
import com.unknow.first.dapp.admin.account.utils.Web3Utils;
import com.unknownman.block.entity.TChainConfig;
import com.unknownman.block.service.TChainConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt;

import java.io.IOException;
import java.util.List;
@Slf4j
@Service
public class AddressRechargeServiceImpl extends ServiceImpl<AddressRechargeMapper, AddressRecharge> implements AddressRechargeService{

    @Autowired
    private TChainConfigService chainConfigService;
    @Autowired
    private DataSourceTransactionManager transactionManager;
    @Autowired
    private AddressAccountInfoService accountInfoService;
    @Autowired
    private AddressCoinConfigService coinConfigService;

    @Override
    public int insertSelective(AddressRecharge record) {
        return baseMapper.insertSelective(record);
    }
    @Override
    public int updateByPrimaryKeySelective(AddressRecharge record) {
        return baseMapper.updateByPrimaryKeySelective(record);
    }
    @Override
    public int updateBatch(List<AddressRecharge> list) {
        return baseMapper.updateBatch(list);
    }
    @Override
    public int batchInsert(List<AddressRecharge> list) {
        return baseMapper.batchInsert(list);
    }

    @Override
    public void processRechargeConfirm() throws IOException {
        //获取未确认充值记录
        List<AddressRecharge> rechargeList = list(
                Wrappers.lambdaQuery(AddressRecharge.class)
                        .eq(AddressRecharge::getStatus, AccountConstants.RechargeStatus.CONFIRM_ING.value)
        );
        if (ObjectUtils.isEmpty(rechargeList)){
            return;
        }
        //获取默认配置的链，此处写法仅支持系统配置一条链
        TChainConfig chainConfig = chainConfigService.getOne(null, false);
        Web3j web3j = Web3Utils.single().web3j();
        long nowBlockNumber = web3j.ethBlockNumber().send().getBlockNumber().longValue();
        for (AddressRecharge recharge : rechargeList) {
            //是否到了确认区块
            if (recharge.getBlockNumber() + chainConfig.getConfirmBlock() > nowBlockNumber){
                continue;
            }
            EthGetTransactionReceipt ethGetTransactionReceipt = web3j.ethGetTransactionReceipt(recharge.getTransactionHash()).send();
            if (ethGetTransactionReceipt.hasError()){
                log.warn("处理充值确认时，获取交易收据请求不成功 - [hash:{}, web3j-error:{}]", recharge.getTransactionHash(), ethGetTransactionReceipt.getError().getMessage());
                continue;
            }
            //交易是否成功
            boolean success = ethGetTransactionReceipt.getTransactionReceipt().isPresent() && ethGetTransactionReceipt.getTransactionReceipt().get().isStatusOK();
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus status = transactionManager.getTransaction(def);
            try {
                if (success){
                    AddressCoinConfig coin = coinConfigService.getByCoinId(recharge.getCoinId());
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put(AccountConstants.TradeRemarkColumn.PAY_BY.code, coin.getPayContract());
                    jsonObject.put("tokenContract", coin.getTokenContract());
                    //更新状态
                    int updateConfirmSuccess = getBaseMapper().updateStatusDone(recharge.getId());
                    Assert.isTrue(updateConfirmSuccess > 0, "更新充值成功状态操作失败, id: " + recharge.getId());
                    //准备入账
                    accountInfoService.processFundAndDetail(recharge.getRealAmount(), coin, AccountConstants.TradeType.PAY, jsonObject.toJSONString(),
                            recharge.getId(), recharge.getAddress(), "System");
                }else {
                    getBaseMapper().updateConfirmFail(recharge.getId());
                }
                transactionManager.commit(status);
            } catch (Exception e) {
                transactionManager.rollback(status);
                log.error("{},{}", e.getMessage(), e);
                e.printStackTrace();
            }
        }
    }
}
